#include <unistd.h>
#include <pthread.h>
#include <errno.h>

pthread_cond_t wait_th1 = PTHREAD_COND_INITIALIZER;
pthread_cond_t wait_th2 = PTHREAD_COND_INITIALIZER;
pthread_cond_t wait_th3 = PTHREAD_COND_INITIALIZER;
pthread_cond_t wait_th4 = PTHREAD_COND_INITIALIZER;

pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;;

int current = 0;

void* th1(void *arg) {
	while(1) {
		pthread_mutex_lock(&mtx);
		while(current != 0) {
			pthread_cond_wait(&wait_th4, &mtx);
		}
		current = 1;
		// write 只能放在锁里头
		// 考虑到，下一个线程可能并未在等待条件，只是在在等待 mtx 
		// 而此时 current 已经成立，如果立即释放锁，则可能导致下一个线程先执行
		write(STDOUT_FILENO, "A", 1);
		pthread_mutex_unlock(&mtx);

		pthread_cond_signal(&wait_th1);
		sleep(1);
	}
}


void* th2(void *arg) {
	while(1) {
		pthread_mutex_lock(&mtx);
		while(current != 1) {
			pthread_cond_wait(&wait_th1, &mtx);
		}
		current = 2;
		write(STDOUT_FILENO, "B", 1);
		pthread_mutex_unlock(&mtx);

		pthread_cond_signal(&wait_th2);
		sleep(1);
	}
}

void* th3(void *arg) {
	while(1) {
		pthread_mutex_lock(&mtx);
		while(current != 2) {
			pthread_cond_wait(&wait_th2, &mtx);
		}
		current = 3;
		write(STDOUT_FILENO, "C", 1);
		pthread_mutex_unlock(&mtx);

		pthread_cond_signal(&wait_th3);
		sleep(1);
	}
}

void* th4(void *arg) {
	while(1) {
		pthread_mutex_lock(&mtx);
		while(current != 3) {
			pthread_cond_wait(&wait_th3, &mtx);
		}
		current = 0;
		write(STDOUT_FILENO, "D", 1);
		pthread_mutex_unlock(&mtx);


		pthread_cond_signal(&wait_th4);
		sleep(1);
	}
}


int main() {
	int ret;

	pthread_t tid1, tid2, tid3, tid4;
	ret = pthread_create(&tid1, NULL, th1, NULL);
	if (ret != 0) {
		errno = ret;
		perror("creaet th1");
		return 1;
	}	
	ret = pthread_create(&tid2, NULL, th2, NULL);
	if (ret != 0) {
		errno = ret;
		perror("creaet th1");
		return 1;
	}	
	ret = pthread_create(&tid3, NULL, th3, NULL);
	if (ret != 0) {
		errno = ret;
		perror("creaet th1");
		return 1;
	}	
	ret = pthread_create(&tid4, NULL, th4, NULL);
	if (ret != 0) {
		errno = ret;
		perror("creaet th1");
		return 1;
	}	

	pthread_cond_signal(&wait_th4);

	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);
	pthread_join(tid3, NULL);
	pthread_join(tid4, NULL);
}
